package com.ruoyi.book.util;

import com.microsoft.cognitiveservices.speech.AudioDataStream;
import com.microsoft.cognitiveservices.speech.SpeechConfig;
import com.microsoft.cognitiveservices.speech.SpeechSynthesisResult;
import com.microsoft.cognitiveservices.speech.SpeechSynthesizer;
import com.ruoyi.common.config.RuoYiConfig;

import java.io.*;
import java.net.URL;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicLong;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <!-- ms speech-->
 *         <dependency>
 *             <groupId>com.microsoft.cognitiveservices.speech</groupId>
 *             <artifactId>client-sdk</artifactId>
 *             <version>1.27.0</version>
 *         </dependency>
 */
public class SpeechSynthesis {
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
    private static String speechKey = "d9ce4b9e3e644cc098fa3a64c91904ff";

    private static String speechRegion = "eastus";

    public static void main(String[] args) throws Exception {
        String text=
                "富贵功名，前缘分定，为人切莫欺心。正大光明，忠良善果弥深。些些狂妄天加谴，眼前不遇待时临。问东君（神话传说中的太阳神）因甚，如今祸害相侵。只为心高图罔极，不分上下乱规箴。话表齐天大圣被众天兵押去斩妖台下，绑在降妖柱上，刀砍斧剁，枪刺剑刳，莫想伤及其身。南斗星奋令火部众神，放火煨烧，亦不能烧着。又着雷部众神，以雷屑钉打，越发不能伤损一毫。那大力鬼王与众启奏道：“万岁，这大圣不知是何处学得这护身之法，臣等用刀砍斧剁，雷打火烧，一毫不能伤损，却如之何？”玉帝闻言道：“这厮这等，这等如何处治？”太上老君即奏道：“那猴吃了蟠桃，饮了御酒，又盗了仙丹，——我那五壶丹，有生有熟，被他都吃在肚里。运用三昧火，煅成一块，所以浑做金钢之躯，急不能伤。不若与老道领去，放在‘八卦炉’中，以文武火煅炼。炼出我的丹来，他身自为灰烬矣。”玉帝闻言，即教六丁、六甲，将他解下，付与老君。老君领旨去讫。一壁厢宣二郎显圣，赏赐金花百朵，御酒百瓶，还丹百粒，异宝明珠，锦绣等件，教与义兄弟分享。真君谢恩，回灌江口不题。那老君到兜率宫，将大圣解去绳索，放了穿琵琶骨之器，推入八卦炉中，命看炉的道人，架火的童子，将火煽起煅炼。原来那炉是乾、坎、艮、震、巽、离、坤、兑八卦。他即将身钻在“巽宫”位下。巽乃风也，有风则无火。只是风搅得烟来，把一双眼熏红了，弄做个老害眼病，故唤作“火眼金睛”。真个光阴迅速，不觉七七四十九日，老君的火候俱全。忽一日，开炉取丹。那大圣双手侮（同捂。掩住、遮住、按住的意思）着眼，正自揉搓流涕，只听得炉头声响，猛睁睛看见光明，他就忍不住，将身一纵，跳出丹炉，唿喇的一声，蹬倒八卦炉，往外就走。慌得那架火、看炉，与丁甲一班人来扯，被他一个个都放倒，好似癫痫的白额虎，风狂的独角龙。老君赶上抓一把，被他一捽，捽了个倒栽葱，脱身走了。即去耳中掣出如意棒，迎风幌一幌，碗来粗细，依然拿在手中，不分好歹，却又大乱天宫，打得那九曜星闭门闭户，四天王无影无形。好猴精！有诗为证。诗曰：混元体正合先天，万劫千番只自然。渺渺无为浑太乙，如如不动号初玄。炉中久炼非铅汞，物外长生是本仙。变化无穷还变化，三皈五戒（佛教中以不杀生、不偷盗、不邪淫、不妄语、不饮酒为五戒）总休言。又诗：一点灵光彻太虚，那条拄杖亦如之：或长或短随人用，横竖横排任卷舒。又诗：猿猴道体配人心，心即猿猴意思深。大圣齐天非假论，官封“弼马”是知音。马猿合作心和意，紧缚牢拴莫外寻。万相归真从一理，如来同契住双林（即沙罗双树。传说中佛祖涅槃的地方）。这一番，猴王不分上下，使铁棒东打西敌，更无一神可挡。只打到通明殿里，灵霄殿外。幸有佑圣真君的佐使王灵官执殿。他见大圣纵横，掣金鞭近前挡住道：“泼猴何往！有吾在此切莫猖狂！”这大圣不由分说，举棒就打。那灵官鞭起相迎。两个在灵霄殿前厮浑一处。好杀：赤胆忠良名誉大，欺天诳上声名坏。一低一好幸相持，豪杰英雄同赌赛。铁棒凶，金鞭快，正直无私怎忍耐？这个是太乙雷声应化尊，那个是齐天大圣猿猴怪。金鞭铁棒两家能，都是神宫仙器械。今日在灵霄宝殿弄威风，各展雄才真可爱。一个欺心要夺斗牛宫，一个竭力匡扶玄圣界。苦争不让显神通，鞭棒往来无胜败。他两个斗在一处，胜败未分，早有佑圣真君，又差将佐发文到雷府，调三十六员雷将齐来，把大圣围在垓心，各骋凶恶鏖战。那大圣全无一毫惧色，使一条如意棒，左遮右挡，后架前迎。一时，见那众雷将的刀枪剑戟、鞭简挝锤、钺斧金瓜、旄镰月铲，来的甚紧，他即摇身一变，变做三头六臂；把如意棒幌一幌，变作三条；六只手使开三条棒，好便似纺车儿一般，滴流流，在那垓心里飞舞。众雷神莫能相近。真个是：圆陀陀，光灼灼，亘古常存人怎学？入火不能焚，入水何曾溺？光明一颗摩尼（梵语的音译。宝珠的意思）珠，剑戟刀枪伤不着。也能善，也能恶，眼前善恶凭他作。善时成佛与成仙，恶处披毛并带角。无穷变化闹天宫，雷将神兵不可捉。当时众神把大圣攒在一处，却不能近身，乱嚷乱斗，早惊动玉帝。遂传旨着游奕灵官同翊（yì，辅佐，帮助）圣真君上西方请佛老降伏。那二圣得了旨，径到灵山胜境，雷音宝刹之前，对四金刚、八菩萨礼毕，即烦转达。众神随至宝莲台下启知，如来召请。二圣礼佛三匝（zā，周，绕一圈），侍立台下。如来问：“玉帝何事，烦二圣下临？”二圣即启道：“向时花果山产一猴，在那里弄神通，聚众猴搅乱世界。玉帝降招安旨，封为‘弼马温’，他嫌官小反去。当遣李天王、哪吒太子擒拿未获，复招安他，封做‘齐天大圣’，先有官无禄。着他代管蟠桃园，他即偷桃；又走至瑶池，偷肴，偷酒，搅乱大会；仗酒又暗入兜率宫，偷老君仙丹，反出天宫。玉帝复遣十万天兵，亦不能收伏。后观世音举二郎真君同他义兄弟追杀，他变化多端，亏老君抛金钢琢打重，二郎方得拿住。解赴御前，即命斩之。刀砍斧剁，火烧雷打，俱不能伤，老君奏准领去，以火煅炼。四十九日开鼎，他却又跳出八卦炉，打退天丁，径入通明殿里，灵霄殿外；被佑圣真君的佐使王灵官挡住苦战，又调三十六员雷将，把他困在垓心，终不能相近。事在紧急，因此，玉帝特请如来救驾。”如来闻诏，即对众菩萨道：“汝等在此稳坐法堂，休得乱了禅位，待我炼魔救驾去来。”如来即唤阿傩、迦叶二尊者相随，离了雷音，径至灵霄门外。忽听得喊声震耳，乃三十六员雷将围困着大圣哩。佛祖传法旨：“教雷将停息干戈，放开营所，叫那大圣出来，等我问他有何法力。”众将果退。大圣也收了法像，现出原身近前，怒气昂昂，厉声高叫道：“你是那方善士，敢来止住刀兵问我？”如来笑道：“我是西方极乐世界释迦牟尼尊者，南无（佛教术语。表示对佛法的一种尊敬）阿弥陀佛。今闻你猖狂村野，屡反天宫，不知是何方生长，何年得道，为何这等暴横？”大圣道：“我本：天地生成灵混仙，花果山中一老猿。水帘洞里为家业，拜友寻师悟太玄。炼就长生多少法，学来变化广无边。在因凡间嫌地窄，立心端要住瑶天。灵霄宝殿非他久，历代人王有分传。强者为尊该让我，英雄只此敢争先。”佛祖听言，呵呵冷笑道：“你那厮乃是个猴子成精，焉敢欺心，要夺玉皇上帝尊位？他自幼修持，苦历过一千七百五十劫。每劫该十二万九千六百年。你算，他该多少年数，方能享受此无极大道？你那个初世为人的畜生，如何出此大言！不当人子！不当人子！折了你的寿算！趁早皈依，切莫胡说！但恐遭了毒手，性命顷刻而休，可惜了你的本来面目！”大圣道：“他虽年久修长，也不应久占在此。常言道：‘皇帝轮流做，明年到我家。’只教他搬出去，将天宫让与我，变罢了。若还不让，定要搅乱，永不清平！”佛祖道：“你除了生长变化之法，在有何能，敢占天宫胜境？”大圣道：“我的手段多哩！我有七十二般变化，万劫不老长生。会驾筋斗云，一纵十万八千里。如何坐不得天位？”佛祖道：“我与你打个赌赛；你若有本事，一筋斗打出我这右手掌中，算你赢，再不用动刀兵苦争战，就请玉帝到西方居住，把天宫让你；若不能打出手掌，你还下界为妖，再修几劫，却来争吵。”那大圣闻言，暗笑道：“这如来十分好呆！我老孙一筋斗去十万八千里。他那手掌，方圆不满一尺，如何跳不出去？”急发声道：“既如此说，你可做得主张？”佛祖道：“做得！做得！”伸开右手，却似个荷叶大小。那大圣收了如意棒，抖擞神威，将身一纵，站在佛祖手心里，却道声：“我出去也！”你看他一路云光，无影无形去了。佛祖慧眼观看，见那猴王风车子一般相似不住，只管前进。大圣行时，忽见有五根肉红柱子，撑着一股青气。他道：“此间乃尽头路了。这番回去，如来作证，灵霄殿定是我坐也。”又思量说：“且住！等我留下些记号，方好与如来说话。”拔下一根毫毛，吹口仙气，叫“变！”变作一管浓墨双毫笔，在那中间柱子上写一行大字云：“齐天大圣，到此一游。”写毕，收了毫毛。又不庄尊，却在第一根柱子根下撒了一泡猴尿。翻转筋斗云，径回本处，站在如来掌：“我已去，今来了。你教玉帝让天宫与我。”如来骂道：“我把你这个尿精猴子！你正好不曾离了我掌哩！”大圣道：“你是不知。我去到天尽头，见五根肉红柱，撑着一股青气，我留个记在那里，你敢和我同去看么？”如来道：“不消去，你只自低头看看。”那大圣睁圆火眼金睛，低头看时，原来佛祖右手中指写着“齐天大圣，到此一游。”大指丫里，还有些猴尿臊气。大圣大吃了一惊道：“有这等事！有这等事！我将此字写在撑天柱子上，如何却在他手指上？莫非有个未卜先知的法术？我决不信！不信！等我再去来！”好大圣，急纵身又要跳出，被佛祖翻掌一扑，把这猴王推出西天门外，将五指化作金、木、水、火、土五座联山，唤名“五行山”，轻轻的把他压住。众雷神与阿傩、迦叶，一个个合掌称扬道：“善哉！善哉！当年卵化学为人，立志修行果道真。万劫无移居胜境，一朝有变散精神。欺天罔（wǎng）上思高位，凌圣偷丹乱大伦。恶贯满盈今有报，不知何日得翻身。”如来佛祖殄灭了妖猴，即唤傩、迦叶同转西方极乐世界。时有天蓬、天佑急出灵霄宝殿道：“请如来少待，我主大驾来也。”佛祖闻言，回首瞻仰。须臾，果见八景鸾舆，九光宝盖；声奏玄歌妙乐，咏哦无量神章；散宝花，喷真香，直至佛前谢曰：“多蒙大法收殄妖邪。望如来少停一日，请诸仙做一会筵奉谢。”如来不敢违悖，即合掌谢道：“老僧承大天尊宣命来此，有何法力？还是天尊与众神洪福，敢劳致谢？”玉帝传旨，即着云部众神，分头请三清、四御、五老、六司、七元、八极、九曜、十都、千真万圣，来此赴会，同谢佛恩。又命四大天师、九天仙女，大开玉京金阙、太玄宝宫、洞阳玉馆，请如来高坐七宝灵台。调设各班座位，安排龙肝凤髓，玉液蟠桃。不一时，那玉清元始天尊、上清灵宝天尊、太清道德天尊、五鬙真君、五斗星君、三官四圣、九曜真君、左辅、右弼、天王、哪吒、玄虚一应灵通，对对旌旗，双双幡盖，都捧着明珠异宝，寿果奇花，向佛前拜献曰：“感如来无量法力，收伏妖猴。蒙大天尊设宴，呼唤我等皆来陈谢。请如来将此会立一名，如何？”如来领众神之托曰：“今欲立名，可作个‘安天大会’。”各仙老异口同声，俱道：“好个‘安天大会’！好个‘安天大会’！”言讫，各坐座位，走斝（jiǎ,古代青铜制的酒器）传觞，簪花鼓瑟，果好会也。有诗为证。诗曰：宴设蟠桃猴搅乱，安天大会胜蟠桃。龙旗鸾辂祥光蔼，宝节幢幡（旌旗之类）瑞气飘。仙乐玄歌音韵美，凤箫玉管响声高。琼香缭绕群仙集，宇宙清平贺圣朝。众皆畅然喜会，只见王母娘娘引一班仙子、仙娥、美姬、美女飘飘荡荡舞向佛前，施礼曰：“前被妖猴搅乱蟠桃一会，今蒙如来大法链锁顽猴，喜庆‘安天大会’，无物可谢，今是我净手亲摘大株蟠桃数枚奉献。”真个是：半红半绿喷甘香，艳丽仙根万载长。堪笑武陵源上种，争如天府更奇强！紫纹娇嫩寰中少，缃核清甜世莫双。延寿延年能易体，有缘食者自非常。佛祖合掌向王母谢讫。王母又着仙姬、仙子唱的唱，舞的舞。满会群仙，又皆赏赞。正是：缥缈天香满座，缤纷仙蕊仙花。玉京金阙大荣华，异品奇珍无价。对对与天齐寿，双双万劫增加。桑田沧海任更差，他自无惊无讶。王母正着仙姬仙子歌舞，觥筹交错（酒杯和酒筹交互错杂，形容许多人聚在一起饮酒的热闹情景），不多时，忽又闻得：一阵异香来鼻嗅，惊动满堂星与宿。天仙佛祖把杯停，各各抬头迎目候。霄汉中间现老人，手捧灵芝飞蔼绣。葫芦藏蓄万年丹，宝录名书千纪寿。洞里乾坤任自由，壶中日月随成就。遨游四海乐清闲，散淡十洲容辐辏。曾赴蟠桃醉几遭，醒时明月还依旧。长头大耳短身躯，南极之方称老寿。寿星又到。见玉帝礼毕，又见如来，申谢道：“始闻那妖猴被老君引至兜率宫煅炼，以为必致平安，不期他又反出。干如来善伏此怪，设宴奉谢，故此闻风而来。更无他物可献，特具紫芝瑶草，碧藕金丹奉上。”诗曰：碧藕金丹奉释迦，如来万寿若恒沙。清平永乐三乘锦，康泰长生九品花。无相门中真法王，色空天上是仙家。乾坤大地皆称祖，丈六金身福寿赊。如来欣然领谢。寿星得座，依然走吅传觞。只见赤脚大仙又至。向玉帝前俯囟礼毕，又对佛祖谢道：“深感法力，降伏妖猴。无物可以表敬，特具交梨二颗，火枣数枚奉献。”诗曰：大仙赤脚枣梨香，敬献弥陀寿算长。七宝莲台山样稳，千金花座锦般妆。寿同天地言非谬，福比洪波话岂狂。福寿如期真个是，清闲极乐那西方。如来又称谢了。叫阿傩、迦叶，将各所献之物，一一收起，方向玉帝前谢宴。众各酩酊，只见个巡视灵官来报道：“那大圣伸出头来了。”佛祖道：“不妨，不妨。”袖中只取出一张帖子，上有六个金字：“唵、嘛、呢、叭、咪、吽（hōng）”。递与阿傩，叫贴在那山顶上。这尊者即领帖子，拿出天门，到那五行山顶上，紧紧的贴在一块四方石上。那座山即生根合缝，可运用呼吸之气，手儿爬出，可以摇挣摇挣。阿傩回报道：“已将帖子贴了。”如来即辞了玉帝众神，与二尊者出天门之外，又发一个慈悲心，念动真言咒语，将五行山召一尊土地神祗，会同五方揭谛，居住此山监押。但他饥时，与他铁丸子吃；渴时，与他溶化的铜汁饮。待他灾愆满日，自有人救他。正是：妖猴大胆反天宫，却被如来伏手降。渴饮溶铜挨岁月，饥餐铁弹度时光。天灾苦困遭磨折，人事凄凉喜命长。若得英雄重展挣（这里是挣扎的意思），他年奉佛上西方。又诗曰：伏逞豪强大事兴，降龙伏虎弄乖能。偷桃偷酒游天府，受录承恩在玉京。恶贯满盈身受困，善根不绝气还升。果然脱得如来手，且待唐朝出圣僧。毕竟不知何年何月，方满灾殃，且听下回分解。";
        speech(text,System.currentTimeMillis()+".wav");
    }
    //两个目录，一个保存目录，一个返回用于显示的目录
    public static  String speech(String text,final String fname)throws Exception{
        SpeechConfig speechConfig = SpeechConfig.fromSubscription(speechKey, speechRegion);

        speechConfig.setSpeechSynthesisVoiceName("zh-CN-YunxiNeural");

        SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer(speechConfig);

        // Get text from the console and synthesize to the default speaker.
        // System.out.println("Enter some text that you want to speak >");
        //&nbsp;<p>
        text=htmlFilter(text);
        //System.out.println(text);

        //保存目录
        final String folder= RuoYiConfig.getUploadPath()+"/mp3/";

        File file = new File(folder);
        if(!file.exists())
            file.mkdirs();

        final String savepath=folder+fname;
        System.out.println(savepath);
        //System.out.println(trn+">>>>>>>>>>");
        List<String> files=new ArrayList<>();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, null);

        int index=0;
        int maxwords=1000;
        while (true){
            if(text.length()<=maxwords)
                maxwords=text.length();
            String tp=text.substring(0,maxwords);
            text=text.substring(maxwords);
            if(tp.length()<=0)
                break;

            SpeechSynthesisResult result = synthesizer.SpeakText(tp);
            AudioDataStream stream = AudioDataStream.fromResult(result);
            stream.saveToWavFile(savepath+(++index));//生成位置
            stream.close();
            files.add(savepath+index);

        }
        mergeWavVoice(new File(savepath),files);
        delteTempFiles(files);//删除临时文件
        return "/upload/mp3/"+fname;
    }

    private static void delteTempFiles(List<String> files) {
        for(String s:files){
            boolean b = new File(s).delete();
            System.out.println(s+"被删除了...."+b);
        }
    }


    public static void mergeWavVoice(File file, List<String> inputStreamList) {
        System.out.println(">>>>开始合并处理<<<<");
        List<AudioInputStream> audioInputStreams = new LinkedList<>();
        AtomicLong allLength = new AtomicLong(0L);
        try {
            inputStreamList.forEach(filePath -> {
                try {
                    String bath = filePath.split(":")[0];
                    AudioInputStream ais;
                    // 通过授权url获取音频输入流
                    if ("HTTP".equalsIgnoreCase(bath) || "HTTPS".equalsIgnoreCase(bath)) {
                        ais = AudioSystem.getAudioInputStream(new URL(filePath));
                    } else {
                        ais = AudioSystem.getAudioInputStream(new File(filePath));
                    }
                    allLength.addAndGet(ais.getFrameLength());
                    audioInputStreams.add(ais);

                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("获取wav文件异常!");
                }
            });
            // LinkedList需要迭代器装入Enumeration，才能放入SequenceInputStream
            Enumeration<AudioInputStream> enumeration = Collections.enumeration(audioInputStreams);
            // 合并音频输入流
            SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);
            // 构造在示例帧中具有需要格式和长度的音频输入流
            AudioInputStream finalAudioInputStream = new AudioInputStream(sequenceInputStream,
                    audioInputStreams.get(0).getFormat(), allLength.get());
            // 输出音频流
            AudioSystem.write(finalAudioInputStream, AudioFileFormat.Type.WAVE, file);
            finalAudioInputStream.close();
//            audioInputStreams.forEach(x-> {
//                try {
//                    x.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            });
            System.out.println("合并完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static String htmlFilter(String htmlStr) {
        // 定义script的正则表达式
        String regExScript = "<script[^>]*?>[\\s\\S]*?</script>";
        // 定义style的正则表达式
        String regExStyle = "<style[^>]*?>[\\s\\S]*?</style>";
        // 定义HTML标签的正则表达式
        String regExHtml = "<[^>]+>";

        // 过滤script标签
        Pattern pScript = Pattern.compile(regExScript, Pattern.CASE_INSENSITIVE);
        Matcher mScript = pScript.matcher(htmlStr);
        htmlStr = mScript.replaceAll("");

        Pattern pStyle = Pattern.compile(regExStyle, Pattern.CASE_INSENSITIVE);
        Matcher mStyle = pStyle.matcher(htmlStr);
        htmlStr = mStyle.replaceAll("");

        Pattern pHtml = Pattern.compile(regExHtml, Pattern.CASE_INSENSITIVE);
        Matcher mHtml = pHtml.matcher(htmlStr);
        htmlStr = mHtml.replaceAll("");

        String str = htmlStr.trim();
        str = str.replaceAll("\\s*", "").replaceAll("", "");
        str = str.replaceAll("(&)*nbsp;*", "").replaceAll("", "");
        return str;
    }
}
